/**
 * 
 */
package com.haisen.lee.serviceimpl;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.cyberneko.html.parsers.DOMParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.haisen.lee.domain.FormDictionary;
import com.haisen.lee.service.IDomParserThread;
import com.haisen.lee.util.DOMParserType;
import com.haisen.lee.util.WriteJavaScriptFile;

/**
 * @author Haisen Lee
 * 
 */
public class HtmlDomParserThreadImpl implements IDomParserThread {

	private URL url;
	private DOMParser parser = null;
	private NamedNodeMap htmlAttributes = null;
	private static final DOMParserType selfDomParser = DOMParserType.HTML;
	private Charset charset = null;
	private FormDictionary formDictionary;
	private List<String> scriptList = new ArrayList<String>();
	private NodeList formNodeList = null;
	private ThreadGroup formThreadGroup = null;
	@Autowired
	private WriteJavaScriptFile writeJavaScriptFile;

	/**
	 * 
	 */
	public HtmlDomParserThreadImpl() {
		parser = new DOMParser();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.haisen.lee.service.IDomParserThread#setParserNode(org.w3c.dom.Node)
	 */
	@Override
	public void setParserNode(Node root) {
		// TODO Auto-generated method stub

	}

	public ThreadGroup getFormThreadGroup() {
		return formThreadGroup;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.haisen.lee.service.IDomParserThread#setUrl(java.net.URL)
	 */
	@Override
	public void setUrl(URL url) {
		this.url = url;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		// TODO Auto-generated method stub
		URLConnection urlConnection = null;
		try {
			urlConnection = url.openConnection();
			InputStream is = urlConnection.getInputStream();
			try {
				parser.parse(new InputSource(is));
			} catch (SAXException e) {
				e.printStackTrace();
			}
			Document doc = parser.getDocument();

			// parser Meta for getting charset
			NodeList metaNodeList = doc.getElementsByTagName("META");
			for (int i = 0; i < metaNodeList.getLength(); i++) {
				Node metaNode = metaNodeList.item(i);
				NamedNodeMap metaNodeAttribute = metaNode.getAttributes();
				for (int j = 0; j < metaNodeAttribute.getLength(); j++) {
					Node metaAttributeNode = metaNodeAttribute.item(j);
					if (metaAttributeNode.getNodeName().equalsIgnoreCase(
							"content")) {
						String cotent = metaAttributeNode.getNodeValue();
						if (cotent.contains("charset")) {
							String charsetStr = cotent.substring(
									cotent.lastIndexOf("=") + 1).trim();
							charset = Charset.forName(charsetStr);
						}
					}
				}
			}
			if (charset == null) {
				charset = Charset.defaultCharset();
			}

			// parser form
			// parser Meta for getting charset
			formNodeList = doc.getElementsByTagName("FORM");
			

			NodeList scriptNodeList = doc.getElementsByTagName("SCRIPT");
			for (int i = 0, localScript = 0; i < scriptNodeList.getLength(); i++) {
				Node scriptNode = scriptNodeList.item(i);
				NamedNodeMap scriptNodeAttribute = scriptNode.getAttributes();
				boolean srcFlag = false;
				for (int j = 0; j < scriptNodeAttribute.getLength(); j++) {
					Node scriptAttributeNode = scriptNodeAttribute.item(j);
					if (scriptAttributeNode.getNodeName().equalsIgnoreCase(
							"SRC")) {
						String srcPath = scriptAttributeNode.getNodeValue();
						URL scriptURL = getURLFormSrcPath(url, srcPath);
						srcFlag = true;
						String fileName = transferURLToFileName(scriptURL);
						scriptList.add(fileName);
						writeJavaScriptFile.writeJavaScriptFile(scriptURL,
								fileName);
					}
				}
				if (!srcFlag) {
					String javascriptContent = scriptNode.getTextContent();
					String fileName = url.getHost() + url.getPath()
							+ localScript + ".js";
					scriptList.add(fileName);
					writeJavaScriptFile.writeJavaScriptFile(javascriptContent,
							fileName);
					localScript++;
				}
			}

			formThreadGroup = new ThreadGroup(Thread.currentThread()
					.getThreadGroup(), url.toString());
			
			for (int i = 0; i < formNodeList.getLength(); i++) {
				FormDomParserThreadImpl formDomParserThreadImpl = new FormDomParserThreadImpl();
				formDomParserThreadImpl.setParserNode(formNodeList.item(i));
				formDomParserThreadImpl.setUrl(url);
				formDomParserThreadImpl.setFormDictionary(formDictionary);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private String transferURLToFileName(URL scriptURL) {
		return scriptURL.getHost() + "/" + scriptURL.getPath();
	}

	private URL getURLFormSrcPath(URL url, String srcPath)
			throws MalformedURLException {
		URL scriptSrcURL = null;
		if (srcPath == null || srcPath.length() == 0) {
			return scriptSrcURL;
		} else if (srcPath.indexOf("/") == 0) {
			scriptSrcURL = new URL(url.getProtocol() + "://" + url.getHost()
					+ srcPath);
		} else if (srcPath.indexOf("../") == 0) {
			String path = url.getPath();
			path = path.substring(0, path.lastIndexOf("/"));
			String scriptPath = path.substring(0, path.lastIndexOf("/"))
					+ srcPath.substring(2);
			scriptSrcURL = new URL(url.getProtocol() + "://" + url.getHost()
					+ scriptPath);
		} else {
			String path = url.getPath();
			String scriptPath = path.substring(0, path.lastIndexOf("/") + 1)
					+ srcPath;
			scriptSrcURL = new URL(url.getProtocol() + "://" + url.getHost()
					+ scriptPath);
		}
		return scriptSrcURL;

	}

	public URL getUrl() {
		return url;
	}

	public NamedNodeMap getHtmlAttributes() {
		return htmlAttributes;
	}

	public void setHtmlAttributes(NamedNodeMap htmlAttributes) {
		this.htmlAttributes = htmlAttributes;
	}

	public List<String> getScriptList() {
		return scriptList;
	}

	public void setScriptList(List<String> scriptMap) {
		this.scriptList = scriptMap;
	}

	public Charset getCharset() {
		return charset;
	}

	public void setWriteJavaScriptFile(WriteJavaScriptFile writeJavaScriptFile) {
		this.writeJavaScriptFile = writeJavaScriptFile;
	}

	@Override
	public void setFormDictionary(FormDictionary formDictionary) {
		this.formDictionary = formDictionary;
	}

	@Override
	public String toString() {
		return "selfDomParserType : " + selfDomParser + "\t" + "url : " + url;
	}
}
